/*
 * Copyright (c) 2025 GuoKaiHong (Shenzhen) Technology Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


import { BusinessError } from '@ohos.base'
import util from '@ohos.util';
import log from './Log'
import { Context } from '@kit.AbilityKit';
import fs from '@ohos.file.fs';
import image from '@ohos.multimedia.image';
import Logger from './Logger'
import common from '@ohos.app.ability.common';

/**
 * 文件工具类
 */
const TAG = "FileUtils"

export class FileUtils {
  public static async savePixelMap(filePath: string, pixelMap: image.PixelMap) {
    const packOpts: image.PackingOption = { format: "image/jpeg", quality: 75 };
    const imgPacker = image.createImagePacker();
    //let file: fs.File = fs.openSync(filePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
    //imgPacker.packToFile(pixelMap, file.fd, packOpts);//API-11 开始支持；
    let data: ArrayBuffer = await imgPacker.packing(pixelMap, packOpts);
    FileUtils.saveData2File(filePath, data);
  }

  public static saveData2File(filePath: string, data: ArrayBuffer | string) {
    let file: fs.File;
    try {
      file = fs.openSync(filePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
      fs.writeSync(file.fd, data);
      if (file) {
        fs.closeSync(file);
      }
    } catch (e) {
      console.log(e)
    } finally {

    }
  }

  public static async transfer2Jpeg(srcPath: string, outpath: string) {
    console.debug(TAG, "srcPath:" + srcPath);
    const imageSource = image.createImageSource(srcPath)
    imageSource.createPixelMap();
    Logger.debug(TAG, "imageSource:" + imageSource);
    const imagePackerApi = image.createImagePacker();

    let packOpts: ESObject = { format: "image/jpeg", quality: 100 };
    let data = await imagePackerApi.packing(imageSource, packOpts)
    const writer = fs.openSync(outpath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
    fs.writeSync(writer.fd, data)
    fs.close(writer)
  }

  public static saveBase64Picture2File(base64Picture: string, dstPath: string) {
    let base64Data = base64Picture.split(',')[1];
    //Logger.debug("FileUtil", "base64Data: "+base64Data);
    let base64Helper = new util.Base64Helper();
    let data: Uint8Array = base64Helper.decodeSync(base64Data)
    FileUtils.saveData2File(dstPath, data.buffer);
  }

  public static getBase64DataFromPicture(file: string): string {
    let readFd = fs.openSync(file, fs.OpenMode.READ_ONLY)
    let stream = fs.fdopenStreamSync(readFd.fd, "r")
    let base64Str: string = "";
    try {
      let state = fs.statSync(file);
      let buf = new ArrayBuffer(state.size)
      stream.readSync(buf)
      let base64Helper = new util.Base64Helper();
      base64Str = base64Helper.encodeToStringSync(new Uint8Array(buf));
    } finally {
      stream.close()
      return base64Str;
    }
  }

  public static copyRawDir(context: Context, src: string) {
    let mgr = context.resourceManager;
    if (mgr === undefined) {
      console.log("mgr is undefined")
      return;
    }
    let index = src.lastIndexOf('/');
    let dirPath: string = context.filesDir + "/" + src.substring(0, index);
    Logger.debug("FileUtil", `dirPath: ${dirPath}`);
    let ret = fs.accessSync(dirPath);
    if (ret) {
      return;
    } else {
      fs.mkdirSync(dirPath);
    }
    //  fs.mkdirSync(dirPath);
    let files: string[] = mgr.getRawFileListSync(src)
    for (let index = 0; index < files.length; index++) {
      const element = files[index];
      if (element) {
        let targetPath: string = context.filesDir + "/" + src + files[index];
        //Logger.debug("FileUtil", "targetPath:"+targetPath)
        let srcFile = src + files[index];
        let data = mgr.getRawFdSync(srcFile);

        let destFile: fs.File = fs.openSync(targetPath, fs.OpenMode.CREATE | fs.OpenMode.READ_WRITE);
        let buffSize: number = 1024;
        let buffer: ArrayBuffer = new ArrayBuffer(buffSize);
        let len: number = 0; // 本次读取内容的实际长度
        let readedLen: number = 0; // 记录已读文件长度
        let remainSize = data.length;
        let readSize = remainSize;
        if (remainSize > buffSize) {
          readSize = buffSize;
        }
        while (len = fs.readSync(data.fd, buffer, { offset: data.offset + readedLen, length: readSize })) {
          //Logger.debug("FileUtil", `data.offset -> ${data.offset}, len: ${len}, remainSizee:${remainSize}`)
          fs.writeSync(destFile.fd, buffer, { offset: readedLen, length: len });
          readedLen += len;
          remainSize = data.length - readedLen;
          if (remainSize > buffSize) {
            readSize = buffSize;
          } else {
            readSize = remainSize;
          }
          if (remainSize <= 0) {
            break;
          }
        }
        if (destFile != undefined) {
          fs.closeSync(destFile);
        }
        if (data != undefined) {
          fs.closeSync(data.fd);
        }
      }
    }
  }

  public static copyFromRawFile(context: common.UIAbilityContext, src: string) {
    let mgr = context.resourceManager;
    if (mgr === undefined) {
      console.log("mgr is undefined")
      return;
    }
    let data = mgr.getRawFdSync(src)
    let index = src.lastIndexOf('/');
    let dirPath: string = context.filesDir + "/" + src.substring(0, index);
    let ret = fs.accessSync(dirPath);
    if (ret) {
      return;
    } else {
      fs.mkdirSync(dirPath);
    }
    //let targetPath: string =  this.context.filesDir + "/" + src.substring(index + 1);
    let targetPath: string = context.filesDir + "/" + src;
    Logger.debug("FileUtil", "targetPath:" + targetPath)

    let destFile: fs.File = fs.openSync(targetPath, fs.OpenMode.CREATE | fs.OpenMode.READ_WRITE);
    let buffSize: number = 1024;
    let buffer: ArrayBuffer = new ArrayBuffer(buffSize);
    let len: number = 0; // 本次读取内容的实际长度
    let readedLen: number = 0; // 记录已读文件长度
    let remainSize = data.length;
    let readSize = remainSize;
    if (remainSize > buffSize) {
      readSize = buffSize;
    }
    while (len = fs.readSync(data.fd, buffer, { offset: data.offset + readedLen, length: readSize })) {
      Logger.debug("FileUtil", `data.offset -> ${data.offset}, len: ${len}, remainSizee:${remainSize}`)
      fs.writeSync(destFile.fd, buffer, { offset: readedLen, length: len });
      readedLen += len;
      remainSize = data.length - readedLen;
      if (remainSize > buffSize) {
        readSize = buffSize;
      } else {
        readSize = remainSize;
      }
      if (remainSize <= 0) {
        break;
      }
    }
    if (destFile != undefined) {
      fs.closeSync(destFile);
    }
    if (data != undefined) {
      fs.closeSync(data.fd);
    }
  }

  public static createMultiLevelDirectory(dirPath: string) {
    let currenPath: string = "";
    const folders = dirPath.split('/');
    for (let folder of folders) {
      currenPath += folder + "/";
      try {
        fs.mkdirSync(currenPath)
      } catch (e) {
        Logger.error("mkdir error ->" + e);
      }
    }
  }

  public static addMultiLevelDirectory(parentPath: string, subPath: string) {
    let currentPath: string = parentPath + "/";
    const folders = subPath.split('/');
    for (let folder of folders) {
      currentPath += folder + "/";
      try {
        fs.mkdirSync(currentPath)
      } catch (e) {
        Logger.error("mkdir error ->" + e);
      }
    }
  }


  static TAG = "FileUtils";

  /**
   * 读取rawfile内容
   *
   * @param context 上下文
   * @param path rawfile文件名（包括后缀）
   * @returns Promise对象
   */
  static getRawFileContent(context: Context, path: string): Promise<Uint8Array> {
    try {
      // promise方式读取rawfile内容
      return context.resourceManager.getRawFileContent(path)
    } catch (error) {
      let code = (error as BusinessError).code;
      let message = (error as BusinessError).message;
      log(FileUtils.TAG, `callback getRawFileContent failed, error code: ${code}, message: ${message}.`)
    }
    return null;
  }

  /**
   * Uint8Array转换字符串
   *
   * @param uint8Array Uint8Array对象
   * @returns 字符串
   */
  static uint8Array2Str(uint8Array: Uint8Array): string {
    let decoder = util.TextDecoder.create('utf-8', { ignoreBOM: false });
    return decoder.decodeWithStream(uint8Array, { stream: false });
  }
}